1. 傅里叶变换和滤波

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;
using namespace std;

// 定义 傅里叶变换函数
void mydft(Mat img_input,Mat& out_img,Mat& transform_arr);

int main(){
Mat img,img_gray,img_out,img_transform;
img = imread("/home/v/home.png");
if (img.empty()){
cout<<"can't open the image"<<endl;
return -1;
}

imshow("Img",img);

cvtColor(img,img_gray,COLOR_BGR2GRAY);
imshow("Img_gray",img_gray);

// 傅里叶变换,img_
mydft(img_gray,img_out,img_transform);
imshow("img out",img_out);
waitKey(0);
return 0;
}

// 傅里叶变换到频谱图和复数域结果
void mydft(Mat img_input,Mat& out_img,Mat& transform_arr){

//1. 扩展图像矩阵,为2,3,5的倍数时运算速度快
int m = getOptimalDFTSize(img_input.rows);
int n = getOptimalDFTSize(img_input.cols);
copyMakeBorder(img_input,img_input,0,m-img_input.rows,0,n-img_input.cols,BORDER_CONSTANT,Scalar::all(0));

//2. 创建双通道矩阵planes,用来存储复数的实部和虚部
Mat planes[] = {Mat_<float>(img_input),Mat::zeros(img_input.size(),CV_32F)};

//3. 从单通道数组中创建一个多通道数组:transform_arr。函数的Merge将几个数组合并为一个多通道阵列,即输出数组的每个元素将是输入数组元素的级联
merge(planes,2,transform_arr);

//4. 进行傅里叶变换
dft(transform_arr,transform_arr);

//5. 计算复数的幅值,保存在out_img(频谱图)
split(transform_arr,planes); // 将双通道分为两个单通道,一个表示实部,一个表示虚部
magnitude(planes[0],planes[1],out_img); // 计算复数的幅值,保存在out_img(频谱图)

//6. 前面得到的频谱图数级过大,不好显示,因此转换
out_img +=Scalar(1); // 取对数前所有像素值都+1,防止log0
log(out_img,out_img); // 取对数
normalize(out_img,out_img,0,1,NORM_MINMAX); // 归一化

//7. 裁剪和重分布幅度图象限
out_img = out_img(Rect(0,0,out_img.cols & -2,out_img.rows & -2));

// 重新排列傅里叶图像中的象限,使原点位于图像中心
int cx = out_img.cols/2;
int cy = out_img.rows/2;
Mat q0(out_img,Rect(0,0,cx,cy));
Mat q1(out_img,Rect(cx,0,cx,cy));
Mat q2(out_img,Rect(0,cy,cx,cy));
Mat q3(out_img,Rect(cx,cy,cx,cy));

// 交换象限中心化
Mat tmp;
// 左上和右下进行交换
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
// 右上与左下进行交换
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}